Aprende Python en 10 minutos
Python es un lenguaje de programación de alto nivel e interpretado conocido por su sintaxis concisa y características poderosas. Este tutorial está basado en la última versión de Python 3.13+, ayudándote a aprender Python rápidamente.
1. Escribiendo tu primer programa en Python
Comencemos con un programa simple. Crea un archivo llamado hello.py
e ingresa el siguiente código:
print("¡Hola, Mundo!")
Guarda el archivo y ejecuta el siguiente comando en la terminal o línea de comandos:
python hello.py
La salida será:
¡Hola, Mundo!
Este programa simple demuestra la funcionalidad básica de salida de Python. La función print()
se utiliza para mostrar información de texto en la consola.
2. Sintaxis básica
La sintaxis de Python es simple y fácil de entender. Python utiliza la indentación para definir bloques de código, a diferencia de otros lenguajes que usan llaves {}
.
# Esto es un comentario
print("¡Hola, Mundo!")
Reglas básicas de sintaxis en Python:
- Indentación: Por defecto, se usan 4 espacios para indicar el nivel de un bloque de código. Por ejemplo, el código dentro de funciones o bucles debe estar indentado.
- Comentarios: Los comentarios de una sola línea comienzan con
#
, mientras que los comentarios de varias líneas usan comillas triples"""
o'''
. - Sentencias: Normalmente, una sentencia por línea, no se necesita punto y coma
;
al final. - Bloques de código: Definidos por indentación, como en
if
,for
, o cuerpos de funciones.
Ejemplo con comentarios de varias líneas:
"""
Este es un comentario de varias líneas,
que abarca múltiples líneas.
"""
La indentación es una característica clave de la sintaxis de Python, utilizada para definir la estructura jerárquica de los bloques de código:
if True:
print("Esta línea está indentada")
print("Esta línea también está indentada")
print("Esta línea no está indentada")
3. Variables y tipos de datos
En Python, las variables son contenedores para almacenar datos. Python es un lenguaje de tipado dinámico, lo que significa que no necesitas declarar el tipo de una variable de antemano.
Reglas básicas para nombrar variables:
- Los nombres de las variables solo pueden contener letras, números y guiones bajos.
- Los nombres de las variables no pueden comenzar con un número.
- Los nombres de las variables son sensibles a mayúsculas y minúsculas.
- Las palabras clave de Python no pueden usarse como nombres de variables.
Los tipos de las variables se determinan por el valor asignado. Los principales tipos de datos básicos de Python son:
- Entero (int): Por ejemplo,
42
o-10
, sin límite de tamaño. - Flotante (float): Por ejemplo,
3.14
o2.5e3
(notación científica). - Cadena (str): Por ejemplo,
"hola"
o'mundo'
, usando comillas simples o dobles. - Booleano (bool):
True
oFalse
. - Ninguno (None): Representado por
None
, indica nulo o sin valor.
Python soporta sugerencias de tipo para mejorar la legibilidad del código, usadas para verificación estática y soporte en IDE, sin afectar el comportamiento en tiempo de ejecución:
nombre: str = "Alicia"
edad: int = 25
3.1 Tipos numéricos (Number)
Python soporta tres tipos numéricos: entero (int), flotante (float) y complejo (complex).
# Entero
edad = 25
poblacion = 1000000
# Flotante
temperatura = 36.5
pi = 3.14159
# Complejo
numero_complejo = 3 + 4j
3.2 Cadena (String)
Las cadenas son secuencias de caracteres, encerradas en comillas simples o dobles.
comilla_simple = 'Cadena con comilla simple'
comilla_doble = "Cadena con comilla doble"
multilinea = """Esta es una
cadena multilínea"""
Operaciones con cadenas:
texto = "Programación en Python"
print(len(texto)) # Longitud de la cadena
print(texto.upper()) # Convertir a mayúsculas
print(texto.lower()) # Convertir a minúsculas
print(texto[0]) # Acceder al primer carácter
print(texto[2:6]) # Segmentación de la cadena
3.3 Tipo booleano (Boolean)
El tipo booleano tiene dos valores: True
y False
.
esta_activo = True
esta_completado = False
# Operaciones booleanas
resultado1 = True and False # False
resultado2 = True or False # True
resultado3 = not True # False
3.4 Tipo Ninguno (None)
None
representa un estado nulo o sin valor.
valor = None
if valor is None:
print("El valor es nulo")
4. Estructuras de datos
Python proporciona varias estructuras de datos integradas para almacenar y manipular datos. A continuación, se presentan las estructuras de datos más comunes y su uso.
4.1 Lista (List)
Una lista es una colección ordenada y mutable. Puedes agregar, eliminar o modificar elementos en una lista. Las listas se definen usando corchetes []
.
numeros = [1, 2, 3, 4, 5]
numeros.append(6) # Agregar elemento
numeros.insert(0, 0) # Insertar en una posición específica
numeros.remove(3) # Eliminar un valor específico
numeros[0] = 10 # Modificar elemento
print(numeros) # [10, 2, 4, 5, 6]
Segmentación de listas para acceder a sublistas:
numeros = [10, 20, 30, 40, 50]
print(numeros[1:4]) # Salida: [20, 30, 40]
print(numeros[:3]) # Salida: [10, 20, 30]
print(numeros[-2:]) # Salida: [40, 50]
Comprensión de listas:
cuadrados = [x**2 for x in range(5)]
print(cuadrados) # [0, 1, 4, 9, 16]
cuadrados_pares = [x**2 for x in range(10) if x % 2 == 0]
print(cuadrados_pares) # [0, 4, 16, 36, 64]
4.2 Tupla (Tuple)
Una tupla es una colección ordenada pero inmutable. Una vez creada, sus elementos no pueden modificarse. Las tuplas se definen usando paréntesis ()
. Debido a su inmutabilidad, las tuplas son generalmente más rápidas que las listas y pueden usarse como claves de diccionarios.
punto = (10, 20)
x, y = punto # Desempaquetado
print(x, y) # Salida: 10 20
Tuplas de un solo elemento requieren una coma:
tupla_unica = (42,)
4.3 Diccionario (Dict)
Un diccionario es una colección no ordenada (ordenada en Python 3.7+) de pares clave-valor. Cada clave es única y está asociada con un valor. Los diccionarios se definen usando llaves {}
.
estudiante = {
"nombre": "Juan",
"edad": 20,
"carrera": "Ciencias de la Computación"
}
# Accediendo y modificando diccionario
print(estudiante["nombre"])
estudiante["edad"] = 21
estudiante["promedio"] = 3.8
# Acceso seguro
print(estudiante.get("telefono", "No proporcionado"))
# Iterando sobre diccionario
for clave, valor in estudiante.items():
print(f"{clave}: {valor}")
Comprensión de diccionarios:
# Crear un diccionario de cuadrados
diccionario_cuadrados = {x: x**2 for x in range(5)}
print(diccionario_cuadrados) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
# Comprensión de diccionario condicional
diccionario_cuadrados_pares = {x: x**2 for x in range(10) if x % 2 == 0}
print(diccionario_cuadrados_pares) # {0: 0, 2: 4, 4: 16, 6: 36, 8: 64}
4.4 Conjunto (Set)
Un conjunto es una colección no ordenada sin elementos duplicados. Se define usando llaves {}
o set()
.
# Crear un conjunto
frutas = {"manzana", "plátano", "naranja"}
numeros = set([1, 2, 3, 3, 4, 4, 5]) # Eliminación automática de duplicados
print(numeros) # {1, 2, 3, 4, 5}
# Operaciones con conjuntos
conjunto1 = {1, 2, 3, 4}
conjunto2 = {3, 4, 5, 6}
print(conjunto1 | conjunto2) # Unión: {1, 2, 3, 4, 5, 6}
print(conjunto1 & conjunto2) # Intersección: {3, 4}
print(conjunto1 - conjunto2) # Diferencia: {1, 2}
print(conjunto1 ^ conjunto2) # Diferencia simétrica: {1, 2, 5, 6}
5. Operaciones y operadores
Python ofrece un conjunto rico de operadores para diversos cálculos y comparaciones, incluyendo operadores aritméticos, de comparación, lógicos, de bits e identidad.
- Operadores aritméticos:
+
,-
,*
,/
,//
(división entera),%
(módulo),**
(exponenciación). - Operadores de comparación:
==
,!=
,>
,<
,>=
,<=
. - Operadores lógicos:
and
,or
,not
. - Operadores de pertenencia:
in
,not in
. - Operadores de identidad:
is
,is not
.
5.1 Operadores aritméticos
Los operadores aritméticos se utilizan para operaciones matemáticas. La precedencia de los operadores sigue las reglas matemáticas (por ejemplo, **
tiene mayor precedencia que +
o -
). Los paréntesis ()
pueden usarse para cambiar la precedencia.
a, b = 10, 3
print(f"Suma: {a + b}") # 13
print(f"Resta: {a - b}") # 7
print(f"Multiplicación: {a * b}") # 30
print(f"División: {a / b}") # 3.333...
print(f"División entera: {a // b}") # 3
print(f"Módulo: {a % b}") # 1
print(f"Exponenciación: {a ** b}") # 1000
5.2 Operadores de comparación
Los operadores de comparación comparan dos valores y devuelven un booleano (True
o False
).
x, y = 5, 10
print(f"Igual: {x == y}") # False
print(f"No igual: {x != y}") # True
print(f"Mayor que: {x > y}") # False
print(f"Menor que: {x < y}") # True
print(f"Mayor o igual: {x >= y}") # False
print(f"Menor o igual: {x <= y}") # True
5.3 Operadores lógicos
Los operadores lógicos combinan o manipulan valores booleanos (True
o False
), típicamente usados en sentencias condicionales.
a, b = True, False
print(f"Operación AND: {a and b}") # False
print(f"Operación OR: {a or b}") # True
print(f"Operación NOT: {not a}") # False
5.4 Operadores de identidad
El operador is
compara la identidad de dos objetos, verificando si hacen referencia a la misma dirección de memoria (no solo valores iguales). Se diferencia de ==
, que compara contenido.
lista1 = [1, 2, 3]
lista2 = [1, 2, 3]
lista3 = lista1
print(f"lista1 is lista2: {lista1 is lista2}") # False
print(f"lista1 is lista3: {lista1 is lista3}") # True
print(f"lista1 == lista2: {lista1 == lista2}") # True
5.5 Operadores de pertenencia
Los operadores de pertenencia verifican si un valor es miembro de una secuencia (por ejemplo, lista, tupla, cadena, conjunto), devolviendo un booleano.
frutas = ["manzana", "plátano", "naranja"]
print(f"'manzana' in frutas: {'manzana' in frutas}") # True
print(f"'uva' not in frutas: {'uva' not in frutas}") # True
6. Flujo de control
Python proporciona varias sentencias de flujo de control para gestionar el orden de ejecución de un programa.
6.1 Sentencias if
La sentencia if
evalúa una condición y ejecuta su bloque si la condición es True
. Usa elif
y else
para condiciones complejas.
edad = 20
if edad >= 18:
print("Adulto")
elif edad >= 13:
print("Adolescente")
else:
print("Niño")
6.2 Bucles for
El bucle for
itera sobre un objeto iterable (por ejemplo, lista, tupla, cadena o rango).
# Iterando sobre una lista
frutas = ["manzana", "plátano", "cereza"]
for fruta in frutas:
print(fruta)
# Usando range() para bucles
for i in range(5):
print(i) # Salida: 0, 1, 2, 3, 4
6.3 Bucles while
El bucle while
continúa ejecutando un bloque mientras su condición siga siendo True
.
contador = 0
while contador < 5:
print(contador)
contador += 1
- break y continue:
break
sale del bucle,continue
omite la iteración actual.
for i in range(10):
if i == 5:
break
if i % 2 == 0:
continue
print(i) # Salida: 1, 3
6.4 Sentencias match
Introducidas en Python 3.10, las sentencias match
proporcionan un poderoso emparejamiento de patrones estructurales, actuando como una alternativa avanzada a las cadenas if/elif/else
.
estado_http = 200
match estado_http:
case 200 | 201:
print("Éxito")
case 404:
print("No encontrado")
case 500:
print("Error del servidor")
case _: # Comodín, coincide con cualquier otro caso
print("Estado desconocido")
7. Entrada y salida
7.1 Entrada y salida básicas
Usa la función input()
para obtener entrada del usuario y la función print()
para mostrar información.
# Obteniendo entrada del usuario
nombre = input("Por favor, introduce tu nombre: ")
edad = int(input("Por favor, introduce tu edad: "))
# Mostrando información
print("Bienvenido", nombre)
print("Tienes", edad, "años")
7.2 Salida formateada (f-strings)
Introducidas en Python 3.6+, las f-strings (literales de cadena formateados) son una forma conveniente y poderosa de formatear cadenas. Prefija una cadena con f
o F
e inserta variables o expresiones en llaves {}
.
usuario = "Alicia"
articulos = 3
costo_total = 45.5
# Usando f-string para un mensaje formateado
mensaje = f"El usuario {usuario} compró {articulos} artículos por ${costo_total:.2f}."
print(mensaje)
# Expresiones en f-strings
print(f"2 + 3 es igual a {2 + 3}")
Expresiones y llamadas a funciones en f-strings:
ancho = 10
alto = 5
# Usando expresiones en f-strings
area = f"Área del rectángulo: {ancho * alto}"
print(area)
# Llamando funciones
texto = "python"
formateado = f"Mayúsculas: {texto.upper()}, Longitud: {len(texto)}"
print(formateado)
Opciones de formato en f-strings:
pi = 3.14159265359
numero_grande = 1234567
# Formato de números
print(f"Pi (2 decimales): {pi:.2f}")
print(f"Pi (4 decimales): {pi:.4f}")
print(f"Número grande (miles): {numero_grande:,}")
print(f"Porcentaje: {0.85:.1%}")
# Alineación de cadenas
nombre = "Python"
print(f"Alineación a la izquierda: '{nombre:<10}'")
print(f"Alineación a la derecha: '{nombre:>10}'")
print(f"Alineación al centro: '{nombre:^10}'")
Formateo de fecha y hora con f-strings:
from datetime import datetime
ahora = datetime.now()
print(f"Hora actual: {ahora}")
print(f"Hora formateada: {ahora:%Y-%m-%d %H:%M:%S}")
print(f"Solo fecha: {ahora:%Y-%m-%d}")
9. Funciones
Las funciones en Python son bloques de código reutilizables para tareas específicas, definidas usando la palabra clave def
, con soporte para parámetros predeterminados, argumentos variables y argumentos de palabra clave.
Definición básica de una función:
def saludar(nombre):
"""Función de saludo"""
return f"¡Hola, {nombre}!"
# Llamando a la función
mensaje = saludar("Juan")
print(mensaje)
Argumentos de palabra clave:
Los argumentos de palabra clave se pasan usando la sintaxis nombre_parámetro=valor
.
def saludar(nombre, saludo="Hola"):
return f"{saludo}, {nombre}!"
print(saludar("Alicia")) # Salida: Hola, Alicia!
print(saludar("Bob", "Hola")) # Salida: Hola, Bob!
Argumentos variables:
Los argumentos variables permiten que las funciones acepten un número arbitrario de argumentos, ya sean posicionales (*args
) o de palabra clave (**kwargs
).
# Argumentos posicionales variables (*args)
def sumar_numeros(*args):
return sum(args)
print(sumar_numeros(1, 2, 3, 4)) # Salida: 10
# Argumentos de palabra clave variables (**kwargs)
def imprimir_kwargs(**kwargs):
for clave, valor in kwargs.items():
print(f"{clave}: {valor}")
imprimir_kwargs(nombre="Alicia", edad=25, ciudad="Beijing")
Anotaciones de funciones:
Las anotaciones de funciones agregan metadatos descriptivos a los parámetros y valores de retorno de las funciones, mejorando la legibilidad y la documentación.
def calcular_area(largo: float, ancho: float) -> float:
"""Calcular el área de un rectángulo"""
return largo * ancho
def procesar_usuario(nombre: str, edad: int, activo: bool = True) -> dict:
"""Procesar información del usuario"""
return {
"nombre": nombre,
"edad": edad,
"activo": activo
}
10. Expresiones lambda
Las expresiones lambda crean funciones anónimas, proporcionando una forma concisa de definir funciones pequeñas.
cuadrado = lambda x: x ** 2
print(cuadrado(5)) # Salida: 25
Comúnmente usadas con funciones de orden superior como map
o filter
:
numeros = [1, 2, 3, 4]
cuadrados = list(map(lambda x: x ** 2, numeros))
print(cuadrados) # Salida: [1, 4, 9, 16]
11. Clases y objetos
Python soporta la programación orientada a objetos usando la palabra clave class
:
class Persona:
"""Clase Persona"""
def __init__(self, nombre, edad):
"""Constructor"""
self.nombre = nombre
self.edad = edad
def presentarse(self):
"""Método de presentación"""
return f"Soy {self.nombre}, tengo {self.edad} años"
def cumplir_anios(self):
"""Método de cumpleaños"""
self.edad += 1
return f"{self.nombre} tuvo un cumpleaños, ahora tiene {self.edad} años"
# Creando objetos
persona1 = Persona("Juan", 25)
persona2 = Persona("Jane", 30)
print(persona1.presentarse())
print(persona2.cumplir_anios())
11.1 Atributos de clase e instancia
En Python, los atributos de clase y los atributos de instancia son dos tipos de atributos para almacenar datos en clases y objetos.
- Atributos de clase: Definidos fuera de los métodos, pertenecen a la clase misma y se comparten entre todas las instancias.
- Atributos de instancia: Definidos en métodos (generalmente
__init__
), están vinculados a instancias específicas a través deself
.
class Estudiante:
# Atributos de clase
universidad = "Universidad de Stanford"
conteo_estudiantes = 0
def __init__(self, nombre, carrera):
# Atributos de instancia
self.nombre = nombre
self.carrera = carrera
Estudiante.conteo_estudiantes += 1
@classmethod
def obtener_conteo_estudiantes(cls):
"""Método de clase"""
return cls.conteo_estudiantes
@staticmethod
def es_edad_valida(edad):
"""Método estático"""
return 0 < edad < 150
# Ejemplo de uso
estudiante1 = Estudiante("Juan", "Ciencias de la Computación")
estudiante2 = Estudiante("Jane", "Matemáticas")
print(f"Universidad: {Estudiante.universidad}")
print(f"Total de estudiantes: {Estudiante.obtener_conteo_estudiantes()}")
print(f"Edad válida: {Estudiante.es_edad_valida(20)}")
11.2 Herencia de clases
La herencia permite que una clase (subclase) herede atributos y métodos de otra clase (clase padre), habilitando la reutilización y extensión del código.
class Animal:
def __init__(self, nombre, especie):
self.nombre = nombre
self.especie = especie
def hacer_sonido(self):
return f"{self.nombre} hace un sonido"
def informacion(self):
return f"{self.nombre} es un {self.especie}"
class Perro(Animal):
def __init__(self, nombre, raza):
super().__init__(nombre, "Perro")
self.raza = raza
def hacer_sonido(self):
return f"{self.nombre} ladra"
def buscar(self):
return f"{self.nombre} busca la pelota"
class Gato(Animal):
def __init__(self, nombre, color):
super().__init__(nombre, "Gato")
self.color = color
def hacer_sonido(self):
return f"{self.nombre} maúlla"
def trepar(self):
return f"{self.nombre} trepa un árbol"
# Usando herencia
perro = Perro("Buddy", "Golden Retriever")
gato = Gato("Mimi", "Naranja")
print(perro.informacion())
print(perro.hacer_sonido())
print(perro.buscar())
print(gato.informacion())
print(gato.hacer_sonido())
print(gato.trepar())
11.3 Métodos especiales (Métodos mágicos)
Los métodos especiales (o métodos mágicos) son métodos con doble guion bajo que definen comportamientos específicos, llamados automáticamente por Python en ciertos escenarios.
class Rectangulo:
def __init__(self, ancho, alto):
self.ancho = ancho
self.alto = alto
def __str__(self):
"""Representación en cadena"""
return f"Rectángulo({self.ancho}x{self.alto})"
def __repr__(self):
"""Representación oficial en cadena"""
return f"Rectangulo(ancho={self.ancho}, alto={self.alto})"
def __eq__(self, otro):
"""Comparación de igualdad"""
if isinstance(otro, Rectangulo):
return self.ancho == otro.ancho and self.alto == otro.alto
return False
def __lt__(self, otro):
"""Comparación menor que (por área)"""
if isinstance(otro, Rectangulo):
return self.area() < otro.area()
return NotImplemented
def __add__(self, otro):
"""Operación de suma"""
if isinstance(otro, Rectangulo):
return Rectangulo(self.ancho + otro.ancho, self.alto + otro.alto)
return NotImplemented
def area(self):
"""Calcular área"""
return self.ancho * self.alto
# Usando métodos especiales
rect1 = Rectangulo(3, 4)
rect2 = Rectangulo(5, 6)
rect3 = Rectangulo(3, 4)
print(rect1) # Rectángulo(3x4)
print(repr(rect1)) # Rectangulo(ancho=3, alto=4)
print(rect1 == rect3) # True
print(rect1 < rect2) # True
print(rect1 + rect2) # Rectángulo(8x10)
12. Gestores de contexto
Los gestores de contexto aseguran la adquisición y liberación adecuada de recursos, comúnmente usados con la sentencia with
para la gestión de recursos, como archivos o conexiones a bases de datos.
12.1 Usando gestores de contexto
Las operaciones con archivos son un caso común para los gestores de contexto:
with open("ejemplo.txt", "r") as archivo:
contenido = archivo.read()
print(contenido)
La sentencia with
asegura que el archivo se cierre automáticamente después de las operaciones.
12.2 Gestores de contexto personalizados
Crea gestores de contexto personalizados definiendo los métodos __enter__
y __exit__
:
class ConexionBaseDatos:
def __init__(self, nombre_base_datos):
self.nombre_base_datos = nombre_base_datos
self.conexion = None
def __enter__(self):
"""Llamado al entrar al contexto"""
print(f"Conectando a la base de datos: {self.nombre_base_datos}")
self.conexion = f"Conexión a {self.nombre_base_datos}"
return self.conexion
def __exit__(self, tipo_excepcion, valor_excepcion, rastreo):
"""Llamado al salir del contexto"""
print(f"Cerrando conexión a la base de datos: {self.nombre_base_datos}")
if tipo_excepcion:
print(f"Ocurrió una excepción: {tipo_excepcion.__name__}: {valor_excepcion}")
self.conexion = None
return False # No suprimir excepciones
# Usando gestor de contexto personalizado
with ConexionBaseDatos("base_datos_usuarios") as conn:
print(f"Usando conexión: {conn}")
print("Realizando operaciones en la base de datos...")
Usando el módulo contextlib
para crear gestores de contexto:
from contextlib import contextmanager
import time
@contextmanager
def temporizador(nombre_operacion):
"""Gestor de contexto de temporizador"""
print(f"Iniciando {nombre_operacion}")
tiempo_inicio = time.time()
try:
yield
finally:
tiempo_fin = time.time()
print(f"{nombre_operacion} completada en {tiempo_fin - tiempo_inicio:.2f} segundos")
# Usando gestor de contexto basado en decorador
with temporizador("procesamiento de datos"):
# Simular operación que consume tiempo
time.sleep(1)
print("Procesando datos...")
13. Manejo de excepciones
El manejo de excepciones asegura la robustez del programa, usando try
, except
, else
y finally
para gestionar excepciones.
try:
resultado = 10 / 0
except ZeroDivisionError:
print("¡No se puede dividir por cero!")
else:
print("División exitosa")
finally:
print("Esto siempre se ejecuta")
Salida:
¡No se puede dividir por cero!
Esto siempre se ejecuta
14. Operaciones con archivos
Python proporciona métodos simples para leer y escribir archivos, típicamente usados con gestores de contexto.
14.1 Leyendo archivos
Leyendo el contenido de un archivo de texto:
with open("ejemplo.txt", "r") as archivo:
contenido = archivo.read()
print(contenido)
Leyendo línea por línea:
with open("ejemplo.txt", "r") as archivo:
for linea in archivo:
print(linea.strip())
14.2 Escribiendo archivos
Escribiendo en un archivo de texto:
with open("salida.txt", "w") as archivo:
archivo.write("¡Hola, Python!\n")
Agregando contenido:
with open("salida.txt", "a") as archivo:
archivo.write("Agregando nuevo contenido.\n")
15. Módulos y paquetes
Los módulos son archivos que contienen código Python, y los paquetes son directorios que contienen múltiples módulos. Importa módulos usando import
:
import math
print(math.sqrt(16)) # Salida: 4.0
Ejemplo de módulo personalizado (suponiendo que el archivo se llama mimodulo.py
):
# mimodulo.py
def decir_hola():
return "¡Hola desde el módulo!"
Importando y usando:
import mimodulo
print(mimodulo.decir_hola()) # Salida: ¡Hola desde el módulo!
16. Alcance y espacio de nombres
16.1 Alcance
El alcance define la región donde una variable es accesible. Python sigue la regla LEGB para la búsqueda de variables:
- L (Local): Dentro de una función o método de clase.
- E (Enclosing): En la función externa de una función anidada (cierre).
- G (Global): En el nivel del módulo.
- B (Built-in): Funciones y excepciones integradas como
print()
olen()
.
x = "x global"
def funcion_externa():
x = "x envolvente"
def funcion_interna():
x = "x local"
print(x) # Accede al alcance local x
funcion_interna()
print(x) # Accede al alcance envolvente x
funcion_externa()
print(x) # Accede al alcance global x
Usando global
o nonlocal
para modificar variables de alcance:
x = "global"
def modificar_global():
global x
x = "modificado"
modificar_global()
print(x) # Salida: modificado
16.2 Espacio de nombres
Un espacio de nombres es un mapeo de nombres a objetos, como un diccionario donde las claves son nombres de variables y los valores son los objetos.
Cada módulo, función y clase tiene su propio espacio de nombres, evitando conflictos de nombres. Usa globals()
y locals()
para inspeccionar espacios de nombres.
una_variable = 10
def alguna_funcion():
variable_b = 20
# locals() devuelve el diccionario del espacio de nombres local actual
print(f"Locales: {locals()}")
print(f"Globales: {globals().keys()}") # Imprime las claves del espacio de nombres global
alguna_funcion()
17. Generadores
Los generadores son iteradores especiales que generan valores bajo demanda, en lugar de crear todos los valores de una vez, lo que los hace eficientes en memoria para conjuntos de datos grandes.
Los generadores usan la palabra clave yield
para devolver valores de forma perezosa:
def fibonacci(n):
a, b = 0, 1
for _ in range(n):
yield a
a, b = b, a + b
for num in fibonacci(5):
print(num) # Salida: 0, 1, 1, 2, 3
18. Multihilo
El multihilo permite que un programa realice múltiples operaciones de manera concurrente, útil para tareas limitadas por entrada/salida, como solicitudes de red o operaciones con archivos.
El módulo threading
de Python proporciona herramientas para crear y gestionar hilos. Debido al Global Interpreter Lock (GIL), el multihilo no logra un verdadero paralelismo de CPU en un solo proceso, pero mejora significativamente el rendimiento para tareas limitadas por entrada/salida.
import threading
import time
def trabajador(nombre_hilo):
print(f"Hilo {nombre_hilo} iniciando...")
time.sleep(2) # Simular operación que consume tiempo
print(f"Hilo {nombre_hilo} finalizado.")
# Crear hilos
hilo1 = threading.Thread(target=trabajador, args=("A",))
hilo2 = threading.Thread(target=trabajador, args=("B",))
# Iniciar hilos
hilo1.start()
hilo2.start()
# Esperar a que todos los hilos terminen
hilo1.join()
hilo2.join()
print("Todos los hilos completados.")
19. Programación asíncrona
La programación asíncrona es ideal para escenarios de alta entrada/salida y alta concurrencia, usando un bucle de eventos para gestionar tareas en lugar de hilos.
Python soporta la programación asíncrona a través de la biblioteca asyncio
y la sintaxis async/await
.
async def
: Define una corrutina.await
: Pausa la ejecución de la corrutina, esperando a que un objeto esperable se complete.
import asyncio
async def decir_hola():
print("Hola")
await asyncio.sleep(1) # Sueño no bloqueante, simulando entrada/salida
print("Mundo")
async def principal():
# Crear y esperar una tarea
await asyncio.create_task(decir_hola())
# Ejecutar la corrutina principal
asyncio.run(principal())
Salida:
Hola
Mundo